﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Celeriq.GeneratedTester
{
	public class ListingItem
	{
		public ListingItem()
		{
		}

		public ListingItem(Celeriq.Common.DataItem item)
			: this()
		{
			this.AutoID = (int?)item.ItemArray[0];
			this.State = (string)item.ItemArray[1];
			this.Year = (int?)item.ItemArray[2];
			this.Price = (int?)item.ItemArray[3];
			this.Location = (Celeriq.Common.GeoCode)item.ItemArray[4];
			this.PostDate = (DateTime?)item.ItemArray[5];
		}

		public virtual int? AutoID { get; set; }
		public virtual string State { get; set; }
		public virtual int? Year { get; set; }
		public virtual int? Price { get; set; }
		public virtual Celeriq.Common.GeoCode Location { get; set; }
		public virtual DateTime? PostDate { get; set; }

		public Celeriq.Common.DataItem ToTransfer()
		{
			var retval = new Celeriq.Common.DataItem();
			retval.ItemArray = new object[] { 
				this.AutoID, 
				this.State, 
				this.Year, 
				this.Price, 
				this.Location, 
				this.PostDate, 
			};
			return retval;
		}
	}

	public class ListingQuery
	{
		public ListingQuery()
		{
			this.DimensionValueList = new List<long>();
			this.FieldFilters = new List<Celeriq.Common.FieldFilter>();
			this.FieldSorts = new List<Celeriq.Common.FieldSort>();
			this.PageOffset = 1;
			this.RecordsPerPage = 10;
		}

		public ListingQuery(Celeriq.Common.DataQuery query)
			: this()
		{
			this.DimensionValueList = query.DimensionValueList;
			this.Keyword = query.Keyword;
			this.PageOffset = query.PageOffset;
			this.RecordsPerPage = query.RecordsPerPage;

			if (query.FieldFilters != null)
			{
				foreach (var ff in query.FieldFilters)
				{
					switch (ff.Name)
					{
						case "AutoID":
							this.FieldFilters.Add(new ListingQueryFilterAutoID()
								{
									AutoID = (int?)((Celeriq.Common.IFieldFilter)ff).Value,
									Comparer = ff.Comparer,
								});
							break;
						case "State":
							this.FieldFilters.Add(new ListingQueryFilterState()
								{
									State = (string)((Celeriq.Common.IFieldFilter)ff).Value,
									Comparer = ff.Comparer,
								});
							break;
						case "Year":
							this.FieldFilters.Add(new ListingQueryFilterYear()
								{
									Year = (int?)((Celeriq.Common.IFieldFilter)ff).Value,
									Comparer = ff.Comparer,
								});
							break;
						case "Price":
							this.FieldFilters.Add(new ListingQueryFilterPrice()
								{
									Price = (int?)((Celeriq.Common.IFieldFilter)ff).Value,
									Comparer = ff.Comparer,
								});
							break;
						case "Location":
							this.FieldFilters.Add(new ListingQueryFilterLocation()
								{
									Latitude = (double)((Celeriq.Common.IFieldFilter)ff).Value,
									Longitude = (double)((Celeriq.Common.IFieldFilter)ff).Value2,
									Comparer = ff.Comparer,
								});
							break;
						case "PostDate":
							this.FieldFilters.Add(new ListingQueryFilterPostDate()
								{
									PostDate = (DateTime?)((Celeriq.Common.IFieldFilter)ff).Value,
									Comparer = ff.Comparer,
								});
							break;
						default:
							throw new Exception("Unknown filter!");
					}
				}
			}

			if (query.FieldSorts != null)
			{
				foreach (var fs in query.FieldSorts)
				{
					switch(fs.Name)
					{
						case "AutoID":
							this.FieldSorts.Add(new ListingQueryFieldSortAutoID()
								{
									Name = fs.Name,
									SortDirection = fs.SortDirection,
								});
							break;
						case "State":
							this.FieldSorts.Add(new ListingQueryFieldSortState()
								{
									Name = fs.Name,
									SortDirection = fs.SortDirection,
								});
							break;
						case "Year":
							this.FieldSorts.Add(new ListingQueryFieldSortYear()
								{
									Name = fs.Name,
									SortDirection = fs.SortDirection,
								});
							break;
						case "Price":
							this.FieldSorts.Add(new ListingQueryFieldSortPrice()
								{
									Name = fs.Name,
									SortDirection = fs.SortDirection,
								});
							break;
						case "PostDate":
							this.FieldSorts.Add(new ListingQueryFieldSortPostDate()
								{
									Name = fs.Name,
									SortDirection = fs.SortDirection,
								});
							break;
						default:
							throw new Exception("Unknown sort!");
					}
				}
			}
		}

		public List<long> DimensionValueList { get; private set; }
		public int PageOffset { get; set; }
		public int RecordsPerPage { get; set; }
		public string Keyword { get; set; }
		public List<Celeriq.Common.FieldFilter> FieldFilters { get; private set; }
		public List<Celeriq.Common.FieldSort> FieldSorts { get; private set; }

		public Celeriq.Common.DataQuery ToTransfer()
		{
			var retval = new Celeriq.Common.DataQuery();
			retval.DimensionValueList = this.DimensionValueList;

			retval.FieldFilters = new List<Celeriq.Common.FieldFilter>();
			foreach (var o in this.FieldFilters)
			{
				var newFilter = new Celeriq.Common.FieldFilter()
					{
						Comparer = o.Comparer,
						Name = o.Name,
					};
				((Celeriq.Common.IFieldFilter)newFilter).Value = ((Celeriq.Common.IFieldFilter)o).Value;
				((Celeriq.Common.IFieldFilter)newFilter).Value2 = ((Celeriq.Common.IFieldFilter)o).Value2;
				retval.FieldFilters.Add(newFilter);
			}

			retval.FieldSorts = new List<Celeriq.Common.FieldSort>();
			foreach (var o in this.FieldSorts)
			{
				retval.FieldSorts.Add(new Celeriq.Common.FieldSort()
					{
						Name = o.Name,
						SortDirection = o.SortDirection,
					});
			}

			retval.Keyword = this.Keyword;
			retval.PageOffset = this.PageOffset;
			retval.RecordsPerPage = this.RecordsPerPage;
			return retval;
		}
	}

	#region Filtering

	public class ListingQueryFilterAutoID : Celeriq.Common.FieldFilter, Celeriq.Common.IFieldFilter
	{
		public ListingQueryFilterAutoID()
		{
			this.Name = "AutoID";
		}

		public virtual int? AutoID { get; set; }

		object Celeriq.Common.IFieldFilter.Value
		{
			get { return this.AutoID; }
			set { this.AutoID = (int?)value; }
		}

	}

	public class ListingQueryFilterState : Celeriq.Common.FieldFilter, Celeriq.Common.IFieldFilter
	{
		public ListingQueryFilterState()
		{
			this.Name = "State";
		}

		public virtual string State { get; set; }

		object Celeriq.Common.IFieldFilter.Value
		{
			get { return this.State; }
			set { this.State = (string)value; }
		}

	}

	public class ListingQueryFilterYear : Celeriq.Common.FieldFilter, Celeriq.Common.IFieldFilter
	{
		public ListingQueryFilterYear()
		{
			this.Name = "Year";
		}

		public virtual int? Year { get; set; }

		object Celeriq.Common.IFieldFilter.Value
		{
			get { return this.Year; }
			set { this.Year = (int?)value; }
		}

	}

	public class ListingQueryFilterPrice : Celeriq.Common.FieldFilter, Celeriq.Common.IFieldFilter
	{
		public ListingQueryFilterPrice()
		{
			this.Name = "Price";
		}

		public virtual int? Price { get; set; }

		object Celeriq.Common.IFieldFilter.Value
		{
			get { return this.Price; }
			set { this.Price = (int?)value; }
		}

	}

	public class ListingQueryFilterLocation : Celeriq.Common.GeoCodeFieldFilter, Celeriq.Common.IFieldFilter
	{
		public ListingQueryFilterLocation()
		{
			this.Name = "Location";
		}

	}

	public class ListingQueryFilterPostDate : Celeriq.Common.FieldFilter, Celeriq.Common.IFieldFilter
	{
		public ListingQueryFilterPostDate()
		{
			this.Name = "PostDate";
		}

		public virtual DateTime? PostDate { get; set; }

		object Celeriq.Common.IFieldFilter.Value
		{
			get { return this.PostDate; }
			set { this.PostDate = (DateTime?)value; }
		}

	}

	#endregion

	#region Sorting

	public class ListingQueryFieldSortAutoID : Celeriq.Common.FieldSort, Celeriq.Common.IFieldSort
	{
		public ListingQueryFieldSortAutoID()
		{
			this.Name = "AutoID";
		}
	}

	public class ListingQueryFieldSortState : Celeriq.Common.FieldSort, Celeriq.Common.IFieldSort
	{
		public ListingQueryFieldSortState()
		{
			this.Name = "State";
		}
	}

	public class ListingQueryFieldSortYear : Celeriq.Common.FieldSort, Celeriq.Common.IFieldSort
	{
		public ListingQueryFieldSortYear()
		{
			this.Name = "Year";
		}
	}

	public class ListingQueryFieldSortPrice : Celeriq.Common.FieldSort, Celeriq.Common.IFieldSort
	{
		public ListingQueryFieldSortPrice()
		{
			this.Name = "Price";
		}
	}

	public class ListingQueryFieldSortPostDate : Celeriq.Common.FieldSort, Celeriq.Common.IFieldSort
	{
		public ListingQueryFieldSortPostDate()
		{
			this.Name = "PostDate";
		}
	}

	#endregion

	public class ListingResults
	{
		public ListingResults(Celeriq.Common.DataQueryResults results)
		{
			this.Query = new ListingQuery(results.Query);
			this.RecordList = new List<ListingItem>();
			if (results.RecordList != null)
			{
				foreach (var item in results.RecordList)
				{
					this.RecordList.Add(new ListingItem(item));
				}
			}

			this.DimensionList = new List<Celeriq.Common.DimensionItem>(results.DimensionList);
			this.AllDimensions = new DimensionStore(this);
			this.TotalRecordCount = results.TotalRecordCount;
			this.ComputeTime = results.ComputeTime;
		}

		public virtual List<Celeriq.Common.DimensionItem> DimensionList { get; private set; }
		public virtual ListingQuery Query { get; private set; }
		public virtual List<ListingItem> RecordList { get; set; }
		public virtual int TotalRecordCount { get; private set; }
		public virtual DimensionStore AllDimensions { get; private set; }
		public virtual long ComputeTime { get; private set; }

	}

	public class DimensionStore
	{
		public DimensionStore(ListingResults results)
		{
			PriceDimension = results.DimensionList.FirstOrDefault(x => x.Name == "Price");
			StateDimension = results.DimensionList.FirstOrDefault(x => x.Name == "State");
			YearDimension = results.DimensionList.FirstOrDefault(x => x.Name == "Year");
		}

		public virtual Celeriq.Common.DimensionItem PriceDimension { get; private set; }
		public virtual Celeriq.Common.DimensionItem StateDimension { get; private set; }
		public virtual Celeriq.Common.DimensionItem YearDimension { get; private set; }
	}

	public class RepositoryConnection
	{
		public static System.ServiceModel.ChannelFactory<Celeriq.Common.IDataModel> GetFactory()
		{
			var factory = new System.ServiceModel.ChannelFactory<Celeriq.Common.IDataModel>("RepositoryServiceNetTcpBinding");
			return factory;
		}

		public static void UpdateData(ListingItem item, Celeriq.Common.IDataModel service)
		{
			UpdateData(new List<ListingItem>() { item }, service);
		}

		public static void UpdateData(IEnumerable<ListingItem> list, Celeriq.Common.IDataModel service)
		{
			var l = new List<Celeriq.Common.DataItem>();
			list.ToList().ForEach(x => l.Add(x.ToTransfer()));
			service.UpdateData(l);
		}

		public static void DeleteData(ListingItem item, Celeriq.Common.IDataModel service)
		{
			DeleteData(new List<ListingItem>() { item }, service);
		}

		public static void DeleteData(IEnumerable<ListingItem> list, Celeriq.Common.IDataModel service)
		{
			var l = new List<Celeriq.Common.DataItem>();
			list.ToList().ForEach(x => l.Add(x.ToTransfer()));
			service.DeleteData(l);
		}

		public static ListingResults QueryData(ListingQuery query, Celeriq.Common.IDataModel service)
		{
			return new ListingResults(service.Query(query.ToTransfer()));
		}

	}

}
